/********************************************************************

Write Date: 2011/1/27
Author: Deng Nianchen
>>>> Implement general functions of a smart pointer.

Modify Date: 2011/3/22
Author: Deng Nianchen
>>>> Add cvt() function to support type convertion.
>>>> Add to OOPUtils namespace.
>>>> Use OOPException as exception framework.

Modify Date: 2011/03/24
Author: Deng Nianchen
>>>> Remove support for array pointer. (I think it is unnecessary)

Modify Date: 2011/06/02
Author: Deng Nianchen
>>>> Split Ptr to two classes: HeapPtr and OOPPtr. See HeapPtr.hpp
     and OOPPtr.hpp for detail. Now this file contains only the common
     implementation of HeapPtr and OOPPtr and named PtrBase.
>>>> Add an exception TypeConvertFailException.
>>>> Changes in exceptions follow the change of OOPException.

Modify Date: 2011/07/16
Author: Deng Nianchen
>>>> Move class PtrException and its children to PtrExceptions.hpp

*********************************************************************/
#ifndef PTR_HPP
#define PTR_HPP
#include "OOPUtilsGlobal.hpp"
#include "CommonExceptions.hpp"
#include "PtrExceptions.hpp"
#include "OOPMutex.h"

_OOPUTILS_BEGIN

/**************************************************************************************************
 * <summary> Purpose: The base class of HeapPtr and OOPPtr. Contains common
 * 					 implementation of smart ptr such as pointer operator
 * 					 and dereference operator. </summary>
 *
 * <remarks>  Deng Nianchen, 2011/6/2. </remarks>
 **************************************************************************************************/

 template< class _Ty >
class Ptr : public OOPObject
{

protected:

	_Ty * __pObj;
	OOPMutex __mutex;

public:

	Ptr (_Ty * newPtr);

	virtual ~Ptr ();

	_Ty * operator-> () throw (NullPtrException &);

	const _Ty * operator-> () const throw (NullPtrException &);

	_Ty & operator* () throw (NullPtrException &);

	const _Ty & operator* () const throw (NullPtrException &);

	operator _Ty * ();

	operator const _Ty * () const;

};

/************************************************************************/
/* Constructors & Destructor                                            */
/************************************************************************/

template< class _Ty >
Ptr< _Ty >::Ptr (_Ty * const newPtr) : __pObj (newPtr) {}

template< class _Ty >
Ptr< _Ty >::~Ptr ()
{
	__pObj = NULL;
}

/************************************************************************/
/* Object access functions                                              */
/************************************************************************/

template< class _Ty >
_Ty * OOPUtils::Ptr<_Ty>::operator-> () throw (NullPtrException &)
{
	OOPMutex::ScopedLock scopedLock (__mutex);
	if (__pObj == NULL)
		OOPTHROW (NullPtrException);
	return __pObj;
}

template< class _Ty >
const _Ty * OOPUtils::Ptr<_Ty>::operator-> () const
	throw (NullPtrException &)
{
	OOPMutex::ScopedLock scopedLock (__mutex);
	if (__pObj == NULL)
		OOPTHROW (NullPtrException);
	return __pObj;
}

template< class _Ty >
_Ty & OOPUtils::Ptr<_Ty>::operator* () throw (NullPtrException &)
{
	OOPMutex::ScopedLock scopedLock (__mutex);
	if (__pObj == NULL)
		OOPTHROW (NullPtrException);
	return *__pObj;
}

template< class _Ty >
const _Ty & OOPUtils::Ptr<_Ty>::operator* () const
	throw (NullPtrException &)
{
	OOPMutex::ScopedLock scopedLock (__mutex);
	if (__pObj == NULL)
		OOPTHROW (NullPtrException);
	return *__pObj;
}

template< class _Ty >
OOPUtils::Ptr<_Ty>::operator _Ty * ()
{
	return __pObj;
}

template< class _Ty >
OOPUtils::Ptr<_Ty>::operator const _Ty * () const
{
	return __pObj;
}

_OOPUTILS_END

#endif